package cn.sanli.manage.config;

import cn.sanli.manage.security.JwtAuthorizationFilter;
import cn.sanli.manage.web.JsonResult;
import cn.sanli.manage.web.ServiceCode;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.session.SessionInformationExpiredEvent;
import org.springframework.security.web.session.SessionInformationExpiredStrategy;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

@Slf4j
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    private JwtAuthorizationFilter jwtAuthorizationFilter;

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    //配置加密类型(BCryptPasswordEncoder 官方推荐方法)
    @Bean
    public PasswordEncoder getPassword() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.csrf().disable();
        http.cors();
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

        http.addFilterBefore(jwtAuthorizationFilter, UsernamePasswordAuthenticationFilter.class);

        //在前后端分离使用Spring Security框架时,需要先将自带的登录页面给禁掉,然后将登录请求放到白名单,这样就可以使用Spring Security框架来进行登录验证。
        String[] urls={"/doc.html","/**/*.css","/**/*.js","swagger-resources","v2/api-docs","user/login","user/selectUser"};
        //开始配置授权访问
        http.authorizeRequests()
                .mvcMatchers(urls)//匹配某些请求
                .permitAll()//许可访问(即不需要通过认证)
                .anyRequest().authenticated()//
                .and()
                .formLogin()
                .and()
                .sessionManagement()
                .maximumSessions(1)
                .expiredSessionStrategy(new SessionInformationExpiredStrategy() {
                    @Override
                    public void onExpiredSessionDetected(SessionInformationExpiredEvent event) throws IOException, ServletException {
                        HttpServletResponse response = event.getResponse();
                        response.setContentType("application/json;charset=UTF-8");
                        String message="当前登录已被顶号，请重新操作";
                        JsonResult<Void> jsonResult=JsonResult.fail(ServiceCode. ERROR_CONFLICT,message);
                        JSON.toJSONString(jsonResult);
                        PrintWriter writer = response.getWriter();
                        writer.println(jsonResult);
                        writer.close();
                    }
                });

        http.exceptionHandling().authenticationEntryPoint(new AuthenticationEntryPoint() {
            @Override
            public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
                response.setContentType("application/json; charset=utf-8");//做格式转换,否则无法将中文正确转换
                String message="您当前未登录,请先登录";
                JsonResult<Void> jsonResult=JsonResult.fail(ServiceCode.ERROR_BAD_REQUEST,message);
                //通过引入的fastjson依赖,实现对象和JSOn格式的转换,只需要调用方法即可,简单的多
                JSON.toJSONString(jsonResult);
                PrintWriter writer = response.getWriter();
                writer.println(jsonResult);
                writer.close();
            }
        });
    }
}
